﻿using System;
using System.Collections.ObjectModel;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.Packaging;
using System.IO.IsolatedStorage;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Microsoft.Practices.Composite.Events;
using ShellLight.Contract;
using ShellLight.Contract.Attributes;
using ShellLight.ViewModels;
using ShellLight.Views;
using System.Net;
using System.Windows.Media.Animation;

namespace ShellLight
{
  public partial class MainPage : UserControl
  {
    [ImportMany(AllowRecomposition = true)]
    public ObservableCollection<UICommand> RegisteredCommands { get; set; }

    private IEventAggregator events;
    private SearchWindow searchWindow;
    private bool helpVisible = false; //indicate if help is visible or not
    Storyboard sbHelpContentDelayWebBrowserVisibility;

    public MainPage()
    {
      InitializeComponent();

      DataContext = new MainPageViewModel();
      events = new EventAggregator();

      // Create a catalog and add this XAP to it
      PackageCatalog catalog = new PackageCatalog();
      catalog.AddPackage(Package.Current);

      foreach (var uri in Config.ModuleUris)
      {
        Package.DownloadPackageAsync(uri, (s, p) =>
                                        {
                                          catalog.AddPackage(p);
                                          InitializeCommands();
                                        });
      }

      // Pass the catalog to the MEF and compose the parts
      var container = new CompositionContainer(catalog);
      container.ComposeParts(this);

      this.KeyDown += MainPage_KeyDown;
    
      //setup events for help functionality
      OpenHelpStoryboard.Completed += OpenHelpStoryboard_Completed;
      CloseHelpStoryboard.Completed += CloseHelpStoryboard_Completed;
      HelpContent.SizeChanged += HelpContent_SizeChanged;
      wb.LoadCompleted += wb_LoadCompleted;
      sbHelpContentDelayWebBrowserVisibility = new Storyboard() { Duration = new Duration(new TimeSpan(0, 0, 0, 0, 500)) };
      sbHelpContentDelayWebBrowserVisibility.Completed += sbHelpContentDelay_Completed;
    }



    private void InitializeCommands()
    {

      foreach (var command in RegisteredCommands.Where(c => c.State == UICommandState.Created))
      {
        InitializeScore(command);
        InitializeHelpUrl(command);
        RegisterCommandEvents(command);
        SetupBehaviorBasedOnAttributes(command);

        command.State = UICommandState.Initialized;
      }
    }

    private void SetupBehaviorBasedOnAttributes(UICommand command)
    {
      if (command.HasAttribute<AttachToTrayAttribute>())
      {
        //MessageBox.Show("attach to tray " + command.Name);
        var context = new UICommandContext() { Events = events, RegiseredCommands = RegisteredCommands.ToList() };
        command.Execute(context);
      }
    }

    private void RegisterCommandEvents(UICommand command)
    {
      command.BeforeShow += command_BeforeShow;
      command.AfterShow += command_AfterShow;
    }

    private void InitializeScore(UICommand command)
    {
      if (IsolatedStorageSettings.ApplicationSettings.Contains(command.Id))
      {
        command.Score = (int)IsolatedStorageSettings.ApplicationSettings[command.Id];
        //MessageBox.Show(command.Name + "->" + command.Score.ToString());
      }
    }

    private void InitializeHelpUrl(UICommand command)
    {
      command.HelpUrl = Config.HelpUrlRoot + command.ConventionalHelpName();
    }

    private void IncrementScore(UICommand command)
    {
      var score = 1;
      if (IsolatedStorageSettings.ApplicationSettings.Contains(command.Id))
      {
        score = (int)IsolatedStorageSettings.ApplicationSettings[command.Id] + 1;
      }
      //MessageBox.Show("issolated storage update hits " + score);
      IsolatedStorageSettings.ApplicationSettings[command.Id] = score;
    }

    void command_BeforeShow(object sender, EventArgs e)
    {
      if (searchWindow != null)
      {
        searchWindow.Close();
      }
    }

    void command_AfterShow(object sender, UICommandEventArgs e)
    {
      var datacontext = DataContext as MainPageViewModel;
      var command = sender as UICommand;

      if (command != null)
        IncrementScore(command);
      if (command.IsModal)
      {
        var modalWindow = new ModalWindow(command.View, command.Name);
        modalWindow.Show();
      }
      else if (command.View != null)
      {
        if (command.HasAttribute<AttachToTrayAttribute>())
        {
          if (!datacontext.TrayCommands.Contains(command))
          {
            datacontext.TrayCommands.Add(command);
          }
          else
          {
            var trayWindow = new TrayWindow(command.View, command.Name);
            trayWindow.Show();
          }
        }
        else
        {
          datacontext.CommandInFocus = command;

          if (!datacontext.ActiveCommands.Contains(command))
          {
            datacontext.ActiveCommands.Add(command);
          }
        }

        InitializeHelpContentForCommand(command);
      }

    }

    void MainPage_KeyDown(object sender, KeyEventArgs e)
    {
      if (Keyboard.Modifiers == ModifierKeys.Control && e.Key == Key.F)
      {
        OpenSearchWindow();
      }
      if (e.Key == Key.F1)
      {
        HandleHelpContentTogling();
      }
    }

    private void SearchButton_Click(object sender, RoutedEventArgs e)
    {
      OpenSearchWindow();
    }

    private void OpenSearchWindow()
    {
      //Collaps webbrowser (if it is visible)
      htmlBrush.Redraw();
      wb.Visibility = Visibility.Collapsed;

      searchWindow = new SearchWindow(RegisteredCommands, events);
      searchWindow.VerticalAlignment = VerticalAlignment.Bottom;
      searchWindow.HorizontalAlignment = HorizontalAlignment.Left;
      searchWindow.Closing += searchWindow_Closing;
      searchWindow.Show();

    }


    void searchWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
    {
      
      searchWindow.Closing -= searchWindow_Closing;
      if(helpVisible)
      {
        sbHelpContentDelayWebBrowserVisibility.Begin();
      }
    }


    private void CloseCommandButton_Click(object sender, RoutedEventArgs e)
    {
      CloseHelpContent();

      var datacontext = DataContext as MainPageViewModel;
      if (datacontext.CommandInFocus != null)
      {
        datacontext.ActiveCommands.Remove(datacontext.CommandInFocus);
        datacontext.CommandInFocus = null;
      }
    }


    #region HelpContent funktionality

    void sbHelpContentDelay_Completed(object sender, EventArgs e)
    {
      if(helpVisible)
      {
        wb.Visibility = Visibility.Visible;
      }
    }


    /// <summary>
    /// When a new command is set to focus we need to adjust the gui and load the help content for the specific command
    /// </summary>
    /// <param name="command">The command in focus</param>
    private void InitializeHelpContentForCommand(UICommand command)
    {
      if (helpVisible)
      {
        helpVisible = false;
        //help is already visible from a previous command so we return to initial state 
        //and we laod the new help content
        wb.Source = new Uri(command.HelpUrl, UriKind.Absolute);
        wb.Visibility = Visibility.Collapsed;
        CloseHelpStoryboard.Begin();
      }
      else
      {
        //if the view is already loaded we can set the size of wb else we need to wait for CopmmandContent.SizeChanged
        if (CommandContent.ActualWidth > 0)
        {
          wb.Height = CommandContent.ActualHeight - 30;
          wb.Width = CommandContent.ActualWidth - 30;
          wb.Source = new Uri(command.HelpUrl, UriKind.Absolute);
        }
        else
        {
          CommandContent.SizeChanged += LoadHelpContentAfterGuiIsLoaded;
        }
      }
    }


    /// <summary>
    /// This methos is called each time F1 is called => we toggle between command and help content
    /// </summary>
    private void HandleHelpContentTogling()
    {
      var cmd = (DataContext as MainPageViewModel).CommandInFocus;
      if (cmd != null)
      {
        if (!helpVisible)
        {
          OpenHelpContent();
        }
        else
        {
          CloseHelpContent();
        }
      }
    }

    private void CloseHelpContent()
    {
      //make sure we close down help funktionality 
      htmlBrush.Redraw();
      wb.Visibility = Visibility.Collapsed;
      if (helpVisible)
      {
        CloseHelpStoryboard.Begin();
      }
    }

    private void OpenHelpContent() 
    {
      HelpContent.Visibility = Visibility.Visible;
      htmlBrush.SetSource(wb);
      htmlBrush.Redraw();
      OpenHelpStoryboard.Begin();
    }

    /// <summary>
    /// This method makes sure that we initially loads the content in the webbrowser with the right size
    /// </summary>
    private void LoadHelpContentAfterGuiIsLoaded(object sender, SizeChangedEventArgs e)
    {
      CommandContent.SizeChanged -= LoadHelpContentAfterGuiIsLoaded;
      var cmd = (DataContext as MainPageViewModel).CommandInFocus;
      if (cmd != null)
      {
        if (CommandContent.ActualWidth > 0)
        {
          wb.Height = CommandContent.ActualHeight - 30;
          wb.Width = CommandContent.ActualWidth - 30;
          wb.Source = new Uri(cmd.HelpUrl, UriKind.Absolute);
        }
      }
    }

    /// <summary>
    /// Each time the size of the window is changed we redraw the html.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    void HelpContent_SizeChanged(object sender, SizeChangedEventArgs e)
    {
      if (HelpContent.ActualWidth > 0)
      {
        wb.Height = HelpContent.ActualHeight - 30;
        wb.Width = HelpContent.ActualWidth - 30;
        htmlBrush.Redraw();
      }
    }

    /// <summary>
    /// New help content has been loaded so we redraw
    /// </summary>
    void wb_LoadCompleted(object sender, EventArgs e)
    {
      htmlBrush.SetSource(wb);
      htmlBrush.Redraw();
    }

    /// <summary>
    /// Help has been opened, so we now switch from the painted version to the real webbrowser
    /// </summary>
    void OpenHelpStoryboard_Completed(object sender, EventArgs e)
    {
      wb.Visibility = Visibility.Visible;
      helpVisible = true;
    }

    /// <summary>
    /// The helpcontent is closed
    /// </summary>
    void CloseHelpStoryboard_Completed(object sender, EventArgs e)
    {
      //it is to late to collapse the webbrowser at this point (needs to be done before the storyboard is run)
      helpVisible = false;
      HelpContent.Visibility = Visibility.Collapsed;
    }

    #endregion



  }
}
